local CheckWidgetType = UI.CheckWidgetType
local CheckArgType = UI.CheckArgType
local MakeAccessor = UI.MakeAccessor
local MakeTypeSetter = UI.MakeTypeSetter

--[[ Frame ]]--

local Frame = UI.NewWidgetType("Frame", "LayoutFrame")

Frame.parameters = {
	keyboard = false,
	mouse = false,
	mousewheel = false,
	movable = false,
	resizable = false,
--~ 	backdrop = { -- WARNING !
--~ 		bgFile = nil,
--~ 		edgeFile = nil,
--~ 		tile = false,
--~ 		tileSize = 0,
--~ 		edgeSize = 32,
--~ 		insets = {
--~ 			left = 0,
--~ 			right = 0,
--~ 			top = 0,
--~ 			bottom = 0
--~ 		}
--~ 	},
	bdbcolred = 1,
	bdbcolgreen = 1,
	bdbcolblue = 1,
	bddcolalpha = 1,
	bdcolred = 1,
	bdcolgreen = 1,
	bdcolblue = 1,
	bdcolalpha = 1,
	framelevel = nil,
	framestrata = "PARENT",
	hrleft = 0,
	hrright = 0,
	hrtop = 0,
	hrbottom = 0,
	crleft = 0,
	crright = 0,
	crtop = 0,
	crbottom = 0,
	id = 0,
	maxrwidth = 0,
	maxrheight = 0,
	minrwidth = 0,
	minrheight = 0,
	scale = 1,
	toplevel = false,
	moving = false,
	userplaced = false,
	clamped = false,
}

function Frame:Initialize(o)
	local t = UI.params[o]
	t.layers = {}
	for layer in pairs(UI.ValidDrawLayerName) do
		t.layers[layer] = true
	end
	t.regions = {}
	t.attributes = {}
end

function Frame.prototype:CreateFontString(name, layer, inheritsFrom)
	CheckWidgetType("Frame:CreateFontString", self, "Frame")
	local f = UI.CreateFrame("FontString", name, self, inheritsFrom)
	UI.params[f].layer = layer
	return f
end

function Frame.prototype:CreateTexture(name, layer, inheritsFrom)
	CheckWidgetType("Frame:CreateTexture", self, "Frame")
	local f = UI.CreateFrame("Texture", name, self, inheritsFrom)
	UI.params[f].layer = layer
	return f
end

function Frame.prototype:DisableDrawLayer(layer)
	CheckWidgetType("Frame:DisableDrawLayer", self, "Frame")
	if not UI.ValidDrawLayerName[layer] then
		error("Frame:DisableDrawLayer(), parameter 2 (layer) is an invalid layer name (%s)", tostring(layer))
	end
	local t = UI.params[self]
	t.layers[layer] = false
end

function Frame.prototype:EnableDrawLayer(layer)
	CheckWidgetType("Frame:EnableDrawLayer", self, "Frame")
	if not UI.ValidDrawLayerName[layer] then
		error("Frame:EnableDrawLayer(), parameter 2 (layer) is an invalid layer name (%s)", tostring(layer))
	end
	local t = UI.params[self]
	t.layers[layer] = true
end

function Frame.prototype:EnableKeyboard(enableFlags)
	CheckWidgetType("Frame:EnableKeyboard", self, "Frame")
	-- CheckArgType("Frame:EnableKeyboard", 2, "enableFlags", "boolean", enableFlags)
	local t = UI.params[self]
	t.keyboard = enableFlags and true or false
end

function Frame.prototype:EnableMouse(enableFlags)
	CheckWidgetType("Frame:EnableMouse", self, "Frame")
	-- CheckArgType("Frame:EnableMouse", 2, "enableFlags", "boolean", enableFlags)
	local t = UI.params[self]
	t.mouse = enableFlags and true or false
end

function Frame.prototype:EnableMouseWheel(enableFlags)
	CheckWidgetType("Frame:EnableMouseWheel", self, "Frame")
	-- CheckArgType("Frame:EnableMouseWheel", 2, "enableFlags", "boolean", enableFlags)
	local t = UI.params[self]
	t.mousewheel = enableFlags and true or false
end

MakeAccessor("Frame", "GetBackdrop", "backdrop")
MakeAccessor("Frame", "GetBackdropBorderColor", {"bdbcolred", "bdbcolgreen", "bdbcolblue", "bdbcolalpha"})
MakeAccessor("Frame", "GetBackdropColor", {"bdcolred", "bdcolgreen", "bdcolblue", "bdcolalpha"})

function Frame.prototype:SetBackdrop(tbl)
	CheckWidgetType("Frame:SetBackdrop", self, "Frame")
	local t = UI.params[self]
	if not tbl then
		t.backdrop = nil
		return
	end
	local backdrop = t.backdrop
	if not backdrop then
		backdrop = { insets = {}, }
		t.backdrop = backdrop
	end
	backdrop.bgFile = tbl.bgFile
	backdrop.edgeFile = tbl.edgeFile
	backdrop.tile = tbl.tile
	backdrop.tileSize = tbl.tileSize
	backdrop.edgeSize = tbl.edgeSize
	if tbl.insets then
		backdrop.insets.left = tbl.insets.left
		backdrop.insets.right = tbl.insets.right
		backdrop.insets.top = tbl.insets.top
		backdrop.insets.bottom = tbl.insets.bottom
	end
end


function Frame.prototype:SetBackdropBorderColor(r, g, b, a)
	CheckWidgetType("Frame:SetBackdropBorderColor", self, "Frame")
	local t = UI.params[self]
	t.bdbcolred = r
	t.bdbcolgreen = g
	t.bdbcolblue = b
	t.bdbcolalpha = a
end

function Frame.prototype:SetBackdropColor(r, g, b, a)
	CheckWidgetType("Frame:SetBackdropColor", self, "Frame")
	local t = UI.params[self]
	t.bdcolred = r
	t.bdcolgreen = g
	t.bdcolblue = b
	t.bdcolalpha = a
end

function Frame.prototype:GetChildren()
	CheckWidgetType("Frame:GetChildren", self, "Frame")
	local children = UI.params[self].children
	if children then
		local temp = {}
		for frame in pairs(children) do
			table.insert(temp, frame)
		end
		return unpack(temp)
	end
end

function Frame.prototype:GetRegions()
	CheckWidgetType("Frame:GetRegions", self, "Frame")
	local t = UI.params[self]
	local temp = {}
	for frame in pairs(t.regions) do
		table.insert(temp, frame)
	end
	return unpack(temp)
end

MakeAccessor("Frame", "GetScale", "scale")
function Frame.prototype:GetEffectiveScale()
	if api.incombat() then return end
	CheckWidgetType("Frame:GetEffectiveScale", self, "Frame")
	local t = UI.params[self]
	local scale = t.scale
	if t.parent then
		scale = scale * t.parent:GetEffectiveScale()
	end
	return scale
end

function Frame.prototype:SetScale(scale)
	if api.incombat() then return end
	CheckWidgetType("Frame:SetScale", self, "Frame")
	CheckArgType("Frame:SetScale", 2, "scale", "number", scale)
	local t = UI.params[self]
	t.scale = scale
	t.dirty = true
end

function Frame.prototype:GetFrameLevel()
	CheckWidgetType("Frame:GetFrameLevel", self, "Frame")
	local level = UI.params[self].framelevel
	if not level then
		local parent = self:GetParent()
		if parent then
			level = parent:GetFrameLevel() + 1
		else
			level = 1
		end
	end
	return level
end

function Frame.prototype:GetFrameStrata()
	CheckWidgetType("Frame:GetFrameStrata", self, "Frame")
	local strata = UI.params[self].framestrata
	if strata == "PARENT" then
		local parent = self:GetParent()
		if parent then
			strata = parent:GetFrameStrata()
		else
			strata = "UNKNOWN"
		end
	end
	return strata
end

function Frame.prototype:SetFrameStrata(strata)
	if api.incombat() then return end
	CheckWidgetType("Frame:SetFrameStrata", self, "Frame")
	CheckArgType("Frame:SetFrameStrata", 2, "strata", "string", strata)
	if not UI.ValidFrameStrataName[strata] then
		error(string.format("Invalid Strata name \"%s\"", strata))
	end
	local t = UI.params[self]
	t.framestrata = strata
end

function Frame.prototype:SetFrameLevel(level)
	if api.incombat() then return end
	CheckWidgetType("Frame:SetFrameLevel", self, "Frame")
	CheckArgType("Frame:SetFrameLevel", 2, "level", "number", level)
	local t = UI.params[self]
	t.framelevel = level
end

function Frame.prototype:GetFrameType()
	local class = getmetatable(self).class
	return class.name
end

function Frame.prototype.IsFrameType(type)
	CheckWidgetType("Frame:IsFrameType", self, "Frame")
	CheckArgType("Frame:IsFrameType", 2, "type", "string", type)
	return IsWidgetType(self, type)
end


MakeTypeSetter("Frame", "SetHitRectInsets", {"hrleft", "hrright", "hrtop", "hrbottom"}, {"number", "number", "number", "number"})
MakeAccessor("Frame", "GetHitRectInsets", {"hrleft", "hrright", "hrtop", "hrbottom"})
MakeTypeSetter("Frame", "SetClampRectInsets", {"crleft", "crright", "crtop", "crbottom"}, {"number", "number", "number", "number"})
MakeAccessor("Frame", "GetClampRectInsets", {"crleft", "crright", "crtop", "crbottom"})

MakeAccessor("Frame", "GetID", "id")

MakeAccessor("Frame", "GetMaxResize", {"maxrwidth", "maxrheight"})
MakeAccessor("Frame", "GetMinResize", {"minrwidth", "minrheight"})
MakeTypeSetter("Frame", "SetMaxResize", {"maxrwidth", "maxrheight"}, {"number", "number"})
MakeTypeSetter("Frame", "SetMinResize", {"minrwidth", "minrheight"}, {"number", "number"})

function Frame.prototype:GetNumChildrens()
	CheckWidgetType("Frame:GetNumChildrens", self, "Frame")
	local t = UI.params[self]
	return #t.children
end

function Frame.prototype:GetNumRegions()
	CheckWidgetType("Frame:GetNumRegions", self, "Frame")
	local t = UI.params[self]
	return #t.regions
end

function Frame.prototype:RegisterEvent(event)
	CheckWidgetType("Frame:RegisterEvent", self, "Frame")
	CheckArgType("Frame:RegisterEvent", 2, "event", "string", event)
	UI.RegisterEvent(self, event)
end

function Frame.prototype:IsEventRegistered(event)
	CheckWidgetType("Frame:IsEventRegistered", self, "Frame")
	CheckArgType("Frame:IsEventRegistered", 2, "event", "string", event)
	return UI.IsEventRegistered(self, event)
end

function Frame.prototype:UnregisterEvent(event)
	CheckWidgetType("Frame:UnregisterEvent", self, "Frame")
	CheckArgType("Frame:UnregisterEvent", 2, "event", "string", event)
	UI.UnregisterEvent(self, event)
end

function Frame.prototype:RegisterAllEvents()
	CheckWidgetType("Frame:RegisterAllEvents", self, "Frame")
	UI.RegisterAllEvents(self)
end

function Frame.prototype:UnregisterAllEvents()
	CheckWidgetType("Frame:UnregisterAllEvents", self, "Frame")
	UI.UnregisterAllEvents(self)
end

function Frame.prototype:AllowAttributeChanges()
	CheckWidgetType("Frame:AllowAttributeChanges", self, "Frame")
	if not api.incombat() then
		UI.params[self].locked = nil
	end
end

function Frame.prototype:SetAttribute(name, value)
	CheckWidgetType("Frame:SetAttribute", self, "Frame")
	CheckArgType("Frame:SetAttribute", 2, "name", "string", name)
	local t = UI.params[self]
	if t.locked then
		log("EE Action Failed (in combat)")
		return
	end
	t.attributes[name] = value

	UI.CallScript(self, "OnAttributeChanged", name, value)
end

function Frame.prototype:GetAttribute(name)
	CheckWidgetType("Frame:GetAttribute", self, "Frame")
	CheckArgType("Frame:GetAttribute", 2, "name", "string", name)
	local t = UI.params[self]
	return t.attributes[name]
end

function Frame.prototype:SetID(value)
	CheckWidgetType("Frame:SetID", self, "Frame")
	CheckArgType("Frame:SetID", 2, "value", "number", value)
	local t = UI.params[self]
	t.id = value
	-- print("SETID", t.name, t.id)
end

function Frame.prototype:Lower()
	CheckWidgetType("Frame:Lower", self, "Frame")
	--@FIXME
end

function Frame.prototype:Raise()
	CheckWidgetType("Frame:Raise", self, "Frame")
	--@FIXME
end

function Frame.prototype:RegisterForDrag(...)
	CheckWidgetType("Frame:RegisterForDrag", self, "Frame")
	--@FIXME
end

function Frame.prototype:IsToplevel()
	CheckWidgetType("Frame:IsToplevel", self, "Frame")
	return UI.params[self].toplevel and 1 or nil
end

function Frame.prototype:SetToplevel(level)
	CheckWidgetType("Frame:SetToplevel", self, "Frame")
	UI.params[self].toplevel = level and true or false
end

function Frame.prototype:SetMovable(movable)
	CheckWidgetType("Frame:SetMovable", self, "Frame")
	UI.params[self].movable = movable and true or false
end

function Frame.prototype:SetResizable(movable)
	CheckWidgetType("Frame:SetResizable", self, "Frame")
	UI.params[self].resizable = resizable and true or false
end

function Frame.prototype:CreateTitleRegion()
	CheckWidgetType("Frame:CreateTitleRegion", self, "Frame")
	local f = UI.CreateObject("FontString")
	UI.params[self].titleRegion = f
	UI.params[f].layer = "TITLE"
	UI.Reparent(f, self)
end

function Frame.prototype:GetTitleRegion()
	CheckWidgetType("Frame:GetTitleRegion", self, "Frame")
	return UI.params[self].titleRegion
end

function Frame.prototype:StartMoving()
	CheckWidgetType("Frame:StartMoving", self, "Frame")
	local t = UI.params[self]
	assert(t.movable, "Can not move this frame")
	t.moving = "MOVE"
end

function Frame.prototype:StartSizing(border)
	CheckWidgetType("Frame:StartSizing", self, "Frame")
	local t = UI.params[self]
	assert(t.resizable, "Can not resize this frame")
	assert(UI.ValidFramePointName[border] and border ~= "CENTER", "Invalid anchor point to resize")
	t.moving = border
end

function Frame.prototype:StopMovingOrSizing()
	CheckWidgetType("Frame:StopMovingOrSizing", self, "Frame")
	local t = UI.params[self]
	t.userplaced = true
	t.moving = false
end

function Frame.prototype:SetUserPlaced(b)
	CheckWidgetType("Frame:SetUserPlaced", self, "Frame")
	UI.params[self].userplaced = b and true or false
end

function Frame.prototype:SetClampedToScreen(b)
	CheckWidgetType("Frame:SetClampedToScreen", self, "Frame")
	UI.params[self].clamped = b and true or false
end

function Frame.prototype:IsMouseOver()
	CheckWidgetType("Frame:IsMouseOver", self, "Frame")
	-- local x, y = GetCursorPosition()
	return nil
end

MakeAccessor("Frame", "IsUserPlaced", "userplaced")

UI.RegisterScriptHandlers(Frame,
	"OnLoad", "OnEvent", "OnUpdate",
	"OnShow", "OnHide","OnEnter", "OnLeave",
	"OnDragStart", "OnDragStop", "OnReceiveDrag",
	"OnSizeChanged",
	"OnKeyUp", "OnKeyDown", "OnChar",
	"OnMouseDown", "OnMouseUp", "OnMouseWheel",
	"OnAttributeChanged")
